<template>
  <div id="map"></div>
  <div class="dialog" v-if="dialogData">
    <div class="close" @click="dialogData = null">关闭</div>
    <div style="margin-bottom: 10px">静态属性</div>
    <div v-for="(item, key) in dialogData" :key="key">
      <div v-if="key !== 'results'">{{ key }}：{{ item }}</div>
    </div>
    <div style="margin-top: 10px">计算属性</div>
    <div v-for="(list, key) in dialogData.results" :key="key">
      <div style="margin-top: 10px; color: red">{{ key }}</div>
      <div v-for="(item, index) in list" :key="index">
        {{ `${index}:00：${item}` }}
      </div>
    </div>
  </div>
  <div class="recalculate" @click="recalculate">修改参数并重新计算</div>
  <!-- <textarea v-model="reportFile" class="textarea"></textarea> -->
</template>

<script setup>
import { ref, onMounted } from "@vue/runtime-core";

import { Project, Workspace } from "epanet-js";
import { toGeoJson } from "./untils/EpanetToGeojson";
import { readBinary } from "./untils/EpanetBinary";
import { default as proj4 } from "proj4";

import maplibregl from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";

import pump_icon from "./images/pump.png";
import reservior_icon from "./images/reservior.png";
import tank_icon from "./images/tank.png";
import valve_icon from "./images/valve.png";

import geoJson from "./南沙模型-DN400.json";

let ws;
let model;
let fromProject;
let toProject;
let editData = ref({
  Junction: {},
  Reservior: {},
  Pipe: {},
  Valve: {},
  Pump: {},
  Tank: {},
});
const reportFile = ref("");
const dialogData = ref(null);

let map;
let mapData = {
  Junction: [],
  Reservior: [],
  Pipe: [],
  Valve: [],
  Pump: [],
  Tank: [],
};

function initModel(url) {
  return new Promise((resolve, reject) => {
    readTextFile(url)
      .then((text) => {
        toProject = fromProject = text;
        // console.log("fromProject:", fromProject);
        // Initialise a new Workspace and Project object
        ws = new Workspace();
        model = new Project(ws);
        resolve();
      })
      .catch((error) => {
        console.error("Error reading file:", error);
        reject();
      });
  });
  // 异步读取文件
  async function readTextFile(path, encoding = "utf-8") {
    const file = new URL(path, import.meta.url);
    const response = await fetch(file);
    const text = await response.text();
    return text;
  }
}
function open() {
  // Write a copy of the inp file to the virtual workspace
  ws.writeFile("net1.inp", toProject);
  model.open("net1.inp", "report.rpt", "out.bin");
}
function run() {
  // Runs toolkit methods: EN_open, EN_solveH & EN_close
  model.solveH();
  model.saveH();

  reportFile.value = ws.readFile("report.rpt");
  // const geoJson = toGeoJson(fromProject);
  console.log("geoJson:", geoJson);
  const resultView = ws.readFile("out.bin", "binary");
  const results = readBinary(resultView);
  console.log("results:", results);

  // 数据处理
  console.log("editData:", editData.value);
  geoJson.links.features.forEach((link, index) => {
    if (editData.value.Pipe[link.properties.id]) {
      editData.value.Pipe[link.properties.id].forEach((item) => {
        link.properties[item.type] = item.value;
      });
    }
    link.properties.results = results.results.links[link.id];
    mapData[link.properties.category].push(link);
  });
  geoJson.nodes.features.forEach((node, index) => {
    if (editData.value.Junction[node.properties.id]) {
      editData.value.Junction[node.properties.id].forEach((item) => {
        node.properties[item.type] = item.value;
      });
      // if (temp.type == "pattern") node.properties.demand = 1;
    }
    node.properties.results = results.results.nodes[node.id];
    mapData[node.properties.category].push(node);
  });
  console.log("mapData:", mapData);
}
function close() {
  model.close();
}
function recalculate() {
  setPipe("223214", 11, "Closed");
  open();
  setJunction("72420", 1, 2);
  setJunction(
    "72420",
    2,
    [
      1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011,
      1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
      1024,
    ]
  );
  run();
  close();
  removeAllLayer();
  addLine("Pipe");
  addLine("Valve");
  addLine("Pump");
  addPoint("Junction");
  addPoint("Reservior");
  addPoint("Tank");
  addIcon("Reservior");
  addIcon("Tank");
  addIcon("Valve");
  addIcon("Pump");
}
function getJunction(id, type) {
  const nodeIndex = model.getNodeIndex(id);
  const nodeValue = model.getNodeValue(nodeIndex, type);
  return nodeValue;
}
function setJunction(id, type, value) {
  const nodeIndex = model.getNodeIndex(id);
  let prop;
  switch (type) {
    case 1:
      // 修改节点需水量
      prop = "demand";
      model.setNodeValue(nodeIndex, type, value);
      break;
    case 2:
      prop = "pattern";
      // 修改节点24小时需水量模式
      model.addPattern(id); // 无需水量模式则需要新增
      const patternIndex = model.getPatternIndex(id); // 无需水量模式则需要新增
      model.setPattern(patternIndex, value);
      // model.setNodeValue(nodeIndex, 1, 1);
      model.setNodeValue(nodeIndex, type, patternIndex);
      break;
  }
  if (editData.value.Junction[id]) {
    let find = editData.value.Junction[id].find(
      (item) => item.type === item.prop
    );
    if (find) {
      find = {
        type: prop,
        value: value,
      };
    } else {
      editData.value.Junction[id].push({
        type: prop,
        value: value,
      });
    }
  } else {
    editData.value.Junction[id] = [];
    editData.value.Junction[id].push({
      type: prop,
      value: value,
    });
  }
}
function getPipe(id, type) {
  const linkIndex = model.getLinkIndex(id);
  const linkValue = model.getLinkValue(linkIndex, type);
  return linkValue;
}
function setPipe(id, type, value) {
  let prop;
  switch (type) {
    case 11:
      // 修改管道开关
      prop = "status";
      let lines = fromProject.split("\n");
      for (let i = 0; i <= lines.length - 1; i++) {
        if (lines[i].indexOf(id) !== -1) {
          lines[i] = lines[i].replace(/Open|Closed/, value);
        }
      }
      toProject = lines.join("\n");
      // console.log("toProject:", toProject);
      break;
  }
  if (editData.value.Pipe[id]) {
    let find = editData.value.Pipe[id].find((item) => item.type === item.prop);
    if (find) {
      find = {
        type: prop,
        value: value,
      };
    } else {
      editData.value.Pipe[id].push({
        type: prop,
        value: value,
      });
    }
  } else {
    editData.value.Pipe[id] = [];
    editData.value.Pipe[id].push({
      type: prop,
      value: value,
    });
  }
}
// 创建地图容器
function initMap() {
  map = new maplibregl.Map({
    container: "map", // container id
    style: "https://demotiles.maplibre.org/style.json", // style URL
    center: [113.44, 22.73], // starting position [lng, lat]
    zoom: 10, // starting zoom
  });
}
// 绘制点要素
function addPoint(layerName) {
  // Add a GeoJSON source with 15 points
  map.addSource(layerName, {
    type: "geojson",
    data: { type: "FeatureCollection", features: mapData[layerName] },
  });
  // Add a symbol layer
  map.addLayer({
    id: layerName,
    type: "circle",
    source: layerName,
    paint: {
      "circle-radius": 5,
      "circle-color": "rgba(0, 255, 0, 1)",
    },
  });
}
// 绘制线要素
function addLine(layerName) {
  let color;
  switch (layerName) {
    case "Valve":
      color = "rgba(255, 0, 0, 1)";
      break;
    case "Pump":
      color = "rgba(255, 255, 0, 1)";
      break;
    default:
      color = "rgba(0, 0, 255, 1)";
      break;
  }
  map.addSource(layerName, {
    type: "geojson",
    data: { type: "FeatureCollection", features: mapData[layerName] },
  });
  map.addLayer({
    id: layerName,
    type: "line",
    source: layerName,
    layout: {
      "line-join": "round",
      "line-cap": "round",
    },
    paint: {
      "line-color": color,
      "line-width": 5,
    },
  });
}
// 绘制图标
async function addIcon(layerName) {
  let icon_img;
  let features;
  switch (layerName) {
    case "Valve":
      icon_img = valve_icon;
      features = [];
      mapData[layerName].forEach((item) => {
        features.push({
          type: "Feature",
          geometry: {
            type: "Point",
            coordinates: [
              (item.geometry.coordinates[0][0] +
                item.geometry.coordinates[1][0]) /
                2,
              (item.geometry.coordinates[0][1] +
                item.geometry.coordinates[1][1]) /
                2,
            ],
          },
          properties: item.properties,
        });
      });
      break;
    case "Pump":
      icon_img = pump_icon;
      features = [];
      mapData[layerName].forEach((item) => {
        features.push({
          type: "Feature",
          geometry: {
            type: "Point",
            coordinates: [
              (item.geometry.coordinates[0][0] +
                item.geometry.coordinates[1][0]) /
                2,
              (item.geometry.coordinates[0][1] +
                item.geometry.coordinates[1][1]) /
                2,
            ],
          },
          properties: item.properties,
        });
      });
      break;
    case "Tank":
      icon_img = tank_icon;
      features = mapData[layerName];
      break;
    case "Reservior":
      icon_img = reservior_icon;
      features = mapData[layerName];
      break;
  }
  if (!map.hasImage(`${layerName}_icon`)) {
    let image = await map.loadImage(icon_img);
    map.addImage(`${layerName}_icon`, image.data);
  }
  map.addSource(`${layerName}_icon`, {
    type: "geojson",
    data: { type: "FeatureCollection", features: features },
  });
  map.addLayer({
    id: `${layerName}_icon`,
    type: "symbol",
    source: `${layerName}_icon`,
    layout: {
      "icon-image": `${layerName}_icon`,
      "icon-size": 0.5,
    },
  });
}
// 清除所有图层
function removeAllLayer() {
  let arr = ["Pipe", "Valve", "Pump", "Junction", "Tank", "Reservior"];
  arr.forEach((name) => {
    if (map.getLayer(name)) {
      map.removeLayer(name);
      map.removeSource(name);
    }
    if (map.getLayer(`${name}_icon`)) {
      map.removeLayer(`${name}_icon`);
      map.removeSource(`${name}_icon`);
    }
  });
}
// 绘制底图
function addUnderlay() {
  map.addSource("wms-test-source", {
    type: "raster",
    tiles: [
      "http://t0.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=f69df935f2b4e5d06629d91c56be2809",
      "http://t1.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=f69df935f2b4e5d06629d91c56be2809",
      "http://t2.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=f69df935f2b4e5d06629d91c56be2809",
      "http://t3.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=f69df935f2b4e5d06629d91c56be2809",
    ],
    tileSize: 256,
  });
  map.addLayer({
    id: "tdt-layer",
    type: "raster",
    source: "wms-test-source",
  });
}
function addHandler() {
  map.on("click", "Pipe", (e) => {
    dialogData.value = {
      ...e.features[0].properties,
      results: JSON.parse(e.features[0].properties.results),
    };
  });
  map.on("click", "Junction", (e) => {
    dialogData.value = {
      ...e.features[0].properties,
      results: JSON.parse(e.features[0].properties.results),
    };
  });
  map.on("click", "Reservior_icon", (e) => {
    dialogData.value = {
      ...e.features[0].properties,
      results: JSON.parse(e.features[0].properties.results),
    };
  });
  map.on("click", "Tank_icon", (e) => {
    dialogData.value = {
      ...e.features[0].properties,
      results: JSON.parse(e.features[0].properties.results),
    };
  });
  map.on("click", "Valve_icon", (e) => {
    dialogData.value = {
      ...e.features[0].properties,
      results: JSON.parse(e.features[0].properties.results),
    };
  });
  map.on("click", "Pump_icon", (e) => {
    dialogData.value = {
      ...e.features[0].properties,
      results: JSON.parse(e.features[0].properties.results),
    };
  });
}
// EPSG:2326坐标转WGS 84坐标
function tranformCoordinate(point) {
  // const fromProjection = `PROJCS["Hong Kong 1980 Grid System",GEOGCS["Hong Kong 1980",DATUM["Hong_Kong_1980",SPHEROID["International 1924",6378388,297],TOWGS84[-162.619,-276.959,-161.764,-0.067753,2.243648,1.158828,-1.094246]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4611"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",22.3121333333333],PARAMETER["central_meridian",114.178555555556],PARAMETER["scale_factor",1],PARAMETER["false_easting",836694.05],PARAMETER["false_northing",819069.8],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AUTHORITY["EPSG","2326"]]`;
  const fromProjection = `PROJCS["Beijing 1954 / 3-degree Gauss-Kruger CM 117E",GEOGCS["Beijing 1954",DATUM["Beijing_1954",SPHEROID["Krassowsky 1940",6378245,298.3],TOWGS84[31.4,-144.3,-74.8,0,0,0.814,-0.38]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4214"]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",117],PARAMETER["scale_factor",1],PARAMETER["false_easting",500000],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AUTHORITY["EPSG","2436"]]`;
  const toProjection = `GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]`;
  const newCoordinates = proj4(fromProjection, toProjection, point);
  return [newCoordinates[0] - 3, newCoordinates[1]]; // 返回数组格式
}

onMounted(async () => {
  await initModel("./南沙模型-DN400.inp");
  open();
  run();
  close();
  initMap();
  addHandler();
  map.on("load", () => {
    addUnderlay();
    addLine("Pipe");
    addLine("Valve");
    addLine("Pump");
    addPoint("Junction");
    addPoint("Reservior");
    addPoint("Tank");
    addIcon("Reservior");
    addIcon("Tank");
    addIcon("Valve");
    addIcon("Pump");
  });
});
</script>

<style scoped>
#map {
  width: 100vw;
  height: 100vh;
}
.textarea {
  position: fixed;
  top: 0;
  right: 0;
  width: 530px;
  height: 530px;
}
.dialog {
  position: fixed;
  top: 0;
  right: 0;
  width: 530px;
  height: 530px;
  overflow: auto;
  background: #fff;
  padding: 10px;
}
.close {
  position: absolute;
  top: 10px;
  right: 10px;
  font-size: 20px;
  font-weight: bold;
  cursor: pointer;
}
.recalculate {
  position: absolute;
  top: 10px;
  left: 10px;
  font-size: 20px;
  font-weight: bold;
  cursor: pointer;
  background-color: #fff;
}
</style>
